import axios, { AxiosError } from 'axios';
import type { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig, RequestConfig } from './types';
import { REQUEST_TIMEOUT } from '@/constants';
import { defaultRequestInterceptors, defaultResponseInterceptors } from './config';
import qs from 'qs';

export const PATH_URL = import.meta.env.VITE_API_BASE_PATH;

const abortControllerMap: Map<string, AbortController> = new Map();

const instance: AxiosInstance = axios.create({
  timeout: REQUEST_TIMEOUT,
  baseURL: PATH_URL,
  paramsSerializer: (params) =>
    qs.stringify(params, {
      arrayFormat: 'repeat',
      skipNulls: false,
      allowEmptyArrays: true
    })
});

instance.interceptors.request.use((res: InternalAxiosRequestConfig) => {
  const abortController = new AbortController();
  const url = res.url ?? '';
  res.signal = abortController.signal;
  abortControllerMap.set(import.meta.env.VITE_USE_MOCK === 'true' ? url.replace('/mock', '') : url, abortController);
  return res;
});

instance.interceptors.response.use(
  (res: AxiosResponse) => {
    const url = res.config.url || '';
    // 从map中删除对应的abortController
    abortControllerMap.delete(url);
    return res;
  },
  (err: AxiosError) => {
    console.log('err： ' + err);
    return Promise.reject(err);
  }
);

// 注入默认的拦截器和响应器
instance.interceptors.request.use(defaultRequestInterceptors);
instance.interceptors.response.use(defaultResponseInterceptors);

const service = {
  request: (config: RequestConfig) => {
    return new Promise((resolve, reject) => {
      // 如果请求自带拦截器, 就先进行处理一遍
      if (config.interceptors?.requestInterceptors) {
        config = config.interceptors.requestInterceptors(config as any);
      }

      instance
        .request(config)
        .then((res) => {
          resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  },
  cancelRequest: (url: string | string[]) => {
    const urlList = Array.isArray(url) ? url : [url];
    for (const url of urlList) {
      abortControllerMap.get(url)?.abort();
      abortControllerMap.delete(url);
    }
  },
  cancelAllRequest: () => {
    for (const [_, controller] of abortControllerMap) {
      controller.abort();
    }
    abortControllerMap.clear();
  }
};

export default service;
